iT邦幫忙

2024 iThome 鐵人賽

DAY 20
0
Modern Web

前進React 生態系 : 技術應用與概念解析系列 第 20

Day 20 - 使用 React 19 的 useOptimistic 和 Transitions 打造順暢體驗

  • 分享至 

  • xImage
  •  

useOptimistic

除了昨天介紹的 useFormStatususeActionState 以外,在 React 19 也推出一個 useOptimistic 的 Hook,用來處理樂觀更新。

樂觀更新

樂觀更新是一種提升使用者體驗的方式。在發送請求的過程中,等待後端或 API 的回應可能需要一段時間。這時可以預設會回應成功,讓即時的反饋比較好,不會讓使用者感到延遲。這種方法通常適用於一些失敗影響較小且容易還原的操作,像是按讚、收藏,或是表單回應已送出的情況。但如果是會有重大影響的操作,例如金流處理等,就不建議使用樂觀更新。

useOptimistic 使用

基本結構:

const [optimisticState, addOptimistic] = useOptimistic(
    state,
    // updateFn
    (currentState, optimisticValue) => {
     // 合併當前狀態和樂觀值,並返回新的狀態
    }
  );

參數:

  • state: 初始的狀態。
  • updateFn(currentState, optimisticValue): 會是一個函數,用於生成樂觀狀態。它會接收兩個參數,並返回生成的樂觀狀態。此函數必須是純函數,不應該有任何副作用。currentState 是當前的狀態,optimisticValue 是傳遞的樂觀值,回傳值會是當前狀態和樂觀值合併而成。

返回值:

  • optimisticState: 生成的樂觀狀態。
  • addOptimistic: 當你有樂觀更新時要調用的調度函數。它接受一個參數 optimisticValue,並使用當前的 state 和傳遞的 optimisticValue 來調用 updateFn,來生成新的狀態。

要注意的是, addOptimistic 的函數必須在 Transition 或 action 內使用,不然會出現錯誤。

使用範例

formaction 範例 : 可以參考 React文件範例

Transition 按讚範例 :

import { useOptimistic, useState } from "react";
import { fetchLike } from "./api";

export default function OptimisticLikeButton({ count, setCount }) {
  const [optimisticLikes, setOptimisticLikes] = useOptimistic(
    { count: count },
    (currentState, newLike) => ({ ...currentState, count: newLike })
  );
  const [isPending, startTransition] = useTransition();

  const handleOptimistic = () => {
    startTransition(async () => {
      setOptimisticLikes(count + 1);
      try {
        const response = await fetchLike(count + 1);
        setCount(response);
      } catch (error) {
        setOptimisticLikes(count);
        console.error(error);
      }
    });
  };

  return (
    <button onClick={handleOptimistic}>
      👍 ({optimisticLikes?.count}) {isPending && <span>Updating</span>}
    </button>
  );
}

什麼是 Transitions?

Transitions 是在 React 18 中引入的新概念,用來提高用戶畫面的響應速度,尤其是在性能較慢的設備上。使用 Transitions 可以有效降低某些 UI 更新的優先級,從而提升整體用戶體驗,讓應用程式的使用更加流暢。

區分緊急和非緊急更新

在某些情況下,我們希望能立即對用戶的操作做出回應,例如用戶輸入內容或點擊按鈕等,這些行為應被視為比較緊急的更新。相對而言,當畫面需要切換到另一個畫面時,這些更新則被視為非緊急的。Transitions 的主要功能就是能夠有效區分這兩種情況,確保緊急更新不會受到非緊急更新的影響。

響應性與更新優先級

使用 Transitions 可以在重新渲染期間保持 UI 的響應性。例如,當用戶點擊一個選項時,如果用戶改變主意並選擇另一個選項,系統可以立即對該操作進行回應,而不需要等待第一個選項的內容渲染完成。

在 Transitions 中的狀態更新可以被其他狀態更新中斷。例如如果在 Transition 中更新了一個元件,但隨後有其他的輸入或點擊事件發生,React 將優先處理這些緊急更新,然後再重新開始執行 Transitions 的更新。

另外要注意的是如果有多個 Transitions 同時發生,React 會視為一個整體來進行更新,未來的版本可能會移除這個限制。

useTransition

useTransition 是 React 18 中提供的 Hook,用來管理 Transitions。

使用範例:

import { useTransition } from "react";

function App() {
  const [isPending, startTransition] = useTransition();

  const handleTabChange = (nextTab) => {
    startTransition(() => {
      setTab(nextTab);
    });
  };

  return (
    <div>
      <button onClick={() => handleTabChange("Tab1")}>Tab 1</button>
      <button onClick={() => handleTabChange("Tab2")}>Tab 2</button>
      {isPending && <span>Loading...</span>}
    </div>
  );
}

isPending 是一個 boolean 值,用來標記當前狀態是否正在處理。

startTransition

startTransition 是用來標記某個狀態更新的函式。在無法使用 useTransition 的情況下使用。

const handleTabChange = (nextTab) => {
  startTransition(() => {
    setTab(nextTab);
  });
};

使用時機

  • 大量渲染的場景:在需要頻繁更新 UI 的場景中,應使用 Transitions 來避免 UI 凍結。
  • 非同步操作:在進行非同步操作時(如 使用 API),可以使用 useTransition 來確保 UI 在資料獲取期間依然保持響應。
  • 複雜的 UI 更新:當更新會導致整個頁面或大量元素重新渲染時,使用 Transitions 可以使更新過程更平滑。

參考資料:
https://19.react.dev/reference/react/useOptimistic
https://19.react.dev/reference/react/useTransition
https://19.react.dev/reference/react/startTransition
https://react.dev/blog/2022/03/29/react-v1


上一篇
Day 19 - Server Functions、action prop 與新的 Hooks
下一篇
Day 21 - 掌握 React 19 use API,處理 Context 和非同步資料
系列文
前進React 生態系 : 技術應用與概念解析22
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言